﻿/**
 * DynaGraphics
 *
 * @author		Allen Chou
 * @version		1.2.1 (last update: Dec 3 2008)
 * @link        http://cjcat.blogspot.com
 * @link		http://cjcat2266.deviantart.com
 */

package idv.cjcat.display.dynashape {
	import flash.display.BitmapData;
	import flash.errors.IllegalOperationError;
	
	import idv.cjcat.*;
	import idv.cjcat.display.*;
	import idv.cjcat.geom.*;
	
	/**
	 * The <code>DynaGraphics</code> class lets you use the drawing API dynamically.
	 * <p>
	 * In the ordinaray case, you use the drawing API through the <code>Graphics</code>class.
	 * All the numeric coordinate data you provide to commands such as <code>Graphcis.lineTo()</code> and <code>Graphics.curveTo()</code> are constant values.
	 * The <code>DynaGraphics</code> class is different.
	 * Although it provides similar commands to those of the <code>Graphics</code> class,
	 * you don't pass numeric coordinate data to these commands.
	 * Instead, you pass objects that have the properties <code>x</code> and <code>y</code> defined as the coordinate data.
	 * When a <code>DynaGraphics</code> object is used by a <code>DynaShape</code> object,
	 * not until the <code>DynaShape.render()</code> method is called would the numeric coordinate data of the data objects be accessed to be used by the drawing API.
	 * That is, when there are changes made to the coordinates of your data objects,
	 * each render call would redraw the graphics according to these new coordinates.
	 * </p>
	 * <p>
	 * Think of a <code>DynaGraphics</code> object as an object that stores a series of drawing API commands.
	 * After being added to a <code>DyhaShape</code> object through <code>DynaShape.add()</code>,
	 * these commands would be actually executed on each call of <code>DynaShape.render()</code>.
	 * </p>
	 */
	public class DynaGraphics {
		/** @private */
		internal var _preCommands:Vector.<int> = new Vector.<int>();
		/** @private */
		internal var _preData:Vector.<Object> = new Vector.<Object>();
		
		/**
		 * Whether the <code>DynaGraphics</code> object would be rendered/rerendered.
		 */
		public var active:Boolean = true;
		public var winding:String = "evenOdd";
		
		/**
		 * Moves the drawing position to the coordinate of an object.
		 * @param	targetObj  The object.
		 */
		public function moveTo(targetObj:Object):void {
			if (!CJGeom.isVec2D(targetObj)) throw new IllegalOperationError("The object must have x and y properties defined");
			
			_preCommands.push(DynaGraphicsCommand.MOVE_TO);
			_preData.push(targetObj);
		}
		
		/**
		 * Draws a line from the drawing position to the coordinate of an object.
		 * @param	targetObj  The object.
		 */
		public function lineTo(targetObj:Object):void {
			if (!CJGeom.isVec2D(targetObj)) throw new IllegalOperationError("The object must have x and y properties defined");
			
			_preCommands.push(DynaGraphicsCommand.LINE_TO);
			_preData.push(targetObj);
		}
		
		/**
		 * Draws a curve from the drawing position to the coordinate of a target object, having a contorl object's coordinate as the curve's control point.
		 * @param	controlObj  The control object.
		 * @param	targetObj   The target object.
		 */
		public function curveTo(controlObj:Object, targetObj:Object):void {
			if (!CJGeom.isVec2D(controlObj)) throw new IllegalOperationError("The object must have x and y properties defined");
			if (!CJGeom.isVec2D(targetObj)) throw new IllegalOperationError("The object must have x and y properties defined");
			
			_preCommands.push(DynaGraphicsCommand.CURVE_TO);
			_preData.push(controlObj, targetObj);
		}
		
		/**
		 * Lines through an array of objects.
		 * @param	objs  The array of objects.
		 */
		public function lineThrough(objs:Array):void {
			for each (var obj:Object in objs) {
				if (!CJGeom.isVec2D(obj)) throw new IllegalOperationError("The object must have x and y properties defined");
				
				_preCommands.push(DynaGraphicsCommand.LINE_TO);
				_preData.push(obj);
			}
		}
		
		/**
		 * Curves through an array of objects.
		 * @param	objs  The array of ofjects.
		 */
		public function curveThrough(objs:Array, sharpness:Number = 0.75):void {
			sharpness = CJMath.clamp(sharpness, 0, 1);
			var temp:Array = new Array();
			for each (var obj:Object in objs) {
				if (!CJGeom.isVec2D(obj)) throw new IllegalOperationError("The object must have x and y properties defined");
				temp.push(obj);
			}
			_preCommands.push(DynaGraphicsCommand.CURVE_THROUGH);
			_preData.push(new CurveThroughData(temp, sharpness));
		}
		
		/**
		 * Sets the line style according to a <code>LineStyle</code> object.
		 * @param	lineStyleObj  The <code>LineStyle</code> object.
		 */
		public function lineStyle(lineStyleObj:LineStyle):void {
			_preCommands.push(DynaGraphicsCommand.LINE_STYLE);
			_preData.push(lineStyleObj);
		}
		
		/**
		 * Sets the fill according to a <code>Fill</code> object.
		 * @param	lineStyleObj  The <code>Fill</code> object.
		 */
		public function beginFill(fillObj:Fill):void {
			_preCommands.push(DynaGraphicsCommand.BEGIN_FILL);
			_preData.push(fillObj);
		}
		
		/**
		 * Ends the fill command.
		 */
		public function endFill():void {
			_preCommands.push(DynaGraphicsCommand.END_FILL);
		}
		
		/**
		 * Draws triangles. See the <code>Graphics.drawTriangles()</code> reference for explanations of parameters.
		 * @param	vertices
		 * @param	indices
		 * @param	uvtData
		 */
		public function drawTriangles(vertices:Vector.<Object>, indices:Vector.<int> = null, uvtData:Vector.<Object> = null):void {
			var obj:Object;
			for each (obj in vertices) {
				if (!CJGeom.isVec2D(obj)) throw new IllegalOperationError("Invalid object without defined x and y properties");
			}
			for each (obj in uvtData) {
				if (!CJGeom.isVec2D(obj)) throw new IllegalOperationError("Invalid object without defined x and y properties");
			}
			_preCommands.push(DynaGraphicsCommand.DRAW_TRIANGLES);
			_preData.push(vertices, indices, uvtData);
		}
		
		/**
		 * Sets the fill to a bitmap data.
		 * @param	bmpd  The bitmap data.
		 */
		public function beginBitmapFill(bmpd:BitmapData):void {
			_preCommands.push(DynaGraphicsCommand.BEGIN_BITMAP_FILL);
			_preData.push(bmpd);
		}
		
		/**
		 * Clears all drawing commands.
		 */
		public function clear():void {
			_preCommands = new Vector.<int>();
			_preData = new Vector.<Object>();
		}
		
	}
}